#pragma once
#include "AsMathBasic.h"

class AS_MATH_API AsMathInterval {
public:
	enum Type {
		Close,
		Open
	};
	AsMathInterval();
	AsMathInterval(int low, int up);
	AsMathInterval(int low, int up, bool isOpenLow, bool isOpenUp);
	AsMathInterval(int low, int up, Type stateLow, Type stateUp);
	static AsMathInterval CloseClose(int low, int up);
	static AsMathInterval OpenOpen(int low, int up);
	static AsMathInterval OpenClose(int low, int up);
	static AsMathInterval CloseOpen(int low, int up);

private:
	int low;
	int up;
	char stateLow = Open;
	char stateUp = Close;

public:
	int getLow() const;
	int getUp() const;
	int getMin() const;
	int getMax() const;
	int getLength() const;
	bool isOpenLow() const;
	bool isOpenUp() const;
	bool isCloseLow() const;
	bool isCloseUp() const;

	std::string tostr() const;
	
public:
	void setLow(int low);
	void setUp(int up);
	void setLowOpen(bool isOpen);
	void setUpOpen(bool isOpen);

public:
	bool inRange(int value) const;
	bool outRange(int value) const;

public:
	std::pair<int, int> toPair() const;

public:
	bool operator==(const AsMathInterval& interval) const;
	bool operator!=(const AsMathInterval& interval) const;
	AsMathInterval operator+(int n) const;
	AsMathInterval operator-(int n) const;
	AsMathInterval operator*(int n) const;
	AsMathInterval operator/(int n) const;
	AsMathInterval& operator+=(int n);
	AsMathInterval& operator-=(int n);
	AsMathInterval& operator*=(int n);
	AsMathInterval& operator/=(int n);
	friend class AsMathIntervals;

};

class AS_MATH_API AsMathIntervals {
private:
	std::vector<AsMathInterval> mIntervals;

public:
	bool isEmpty() const;
	std::vector<AsMathInterval> getIntervals() const;

	std::string tostr() const;

public:
	void add(const AsMathInterval& interval);
	void remove(const AsMathInterval& interval);
	void clearInterval();

public:
	bool inRange(int value) const;
	bool outRange(int value) const;

public:
	std::vector<std::pair<int, int>> toPairs() const;

public:
	void operator+=(const AsMathInterval& interval);
	void operator-=(const AsMathInterval& interval);

};

namespace AsMath {

	template <typename _Type>
	std::vector<_Type> in_interval(const std::vector<_Type>& inputArray, const AsMathInterval& interval) {
		std::vector<_Type> outputArray;
		AsMath::traverse_i_const(inputArray, [&](const _Type& elem, int index)->bool {
			if (interval.inRange(index)) {
				outputArray.emplace_back(elem);
			}
			return true;
		});
		return std::move(outputArray);
	}

	template <typename _Type>
	std::vector<_Type> in_intervals(const std::vector<_Type>& inputArray, const AsMathIntervals& intervals) {
		std::vector<_Type> outputArray;
		AsMath::traverse_i_const(inputArray, [&](const _Type& elem, int index)->bool {
			if (intervals.inRange(index)) {
				outputArray.emplace_back(elem);
			}
			return true;
		});
		return std::move(outputArray);
	}

};